package com.qf.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.blog.commons.constants.SysConsts;
import com.qf.blog.commons.exception.BusinessException;
import com.qf.blog.commons.security.UserTokenThreadLocal;
import com.qf.blog.commons.utils.EmailUtils;
import com.qf.blog.commons.utils.MD5Utils;
import com.qf.blog.commons.utils.SaltUtils;
import com.qf.blog.commons.utils.UUIDUtils;
import com.qf.blog.dto.EmailDto;
import com.qf.blog.entity.Letter;
import com.qf.blog.entity.PasswordRecord;
import com.qf.blog.entity.User;
import com.qf.blog.enums.ExceptionEnum;
import com.qf.blog.enums.UserStatusEnum;
import com.qf.blog.enums.UserTypeEnum;
import com.qf.blog.mapper.PasswordRecordMapper;
import com.qf.blog.mapper.UserMapper;
import com.qf.blog.service.ILetterService;
import com.qf.blog.service.IUserService;
import com.qf.blog.vo.LetterVo;
import com.qf.blog.vo.UserToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private ILetterService iLetterService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordRecordMapper pwdRecordMapper;
    @Autowired
    private EmailUtils emailUtils;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public List<LetterVo> queryMessages() {
        Integer userId=UserTokenThreadLocal.getUser().getId();
        List<LetterVo> letterVoList=iLetterService.queryByUserId(userId);
        if (letterVoList.size()==0) {
            return letterVoList;
        }
        QueryWrapper<Letter> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("to_id",userId);
        queryWrapper.eq("status",SysConsts.MesaaggeStatus.UNREAD);
        long count=iLetterService.count(queryWrapper);
        LetterVo letterVo=letterVoList.get(SysConsts.MesaaggeStatus.UNREAD);
        letterVo.setLetterUnreadCount(count);
        letterVoList.set(0,letterVo);
        return letterVoList;
    }

    @Override
    public boolean register(User user) {
        User nameUser = getUserByColumn("username", user.getUsername());
        if (nameUser != null) {
            throw new BusinessException(ExceptionEnum.USERNAME_EXISTS);
        }
        User emailUser = getUserByColumn("email", user.getEmail());
        if (emailUser != null) {
            throw new BusinessException(ExceptionEnum.EMAIL_EXISTS);
        }
        user.setType(UserTypeEnum.REGULAR.getValue());
        String userSalt = SaltUtils.getSalt();
        user.setSalt(userSalt);
        user.setPassword(MD5Utils.md5(user.getPassword() + userSalt));
        int insert = userMapper.insert(user);
        if (insert > 0) {
            log.info("注册成功，创建user：" + user);
            savePwdRecord(user);
            EmailDto emaiDto = new EmailDto();
            String content = String.format(
                    "欢迎注册Blog平台，点击<a href= 'http://127.0.0.1:8080/user/activate/%s'>这里</a>激活",
                    user.getActivationCode()
            );
            emaiDto.setTitle("Blog系用户激活");
            emaiDto.setContent(content);
            emaiDto.setRecipient(user.getEmail());
            try {
                emailUtils.sendEmail(emaiDto);
                log.info("发送激活邮箱成功：" + user.getEmail());
            } catch (Exception e) {
                log.error("发送激活邮箱失败：" + user.getEmail());
                e.printStackTrace();
            }
            return true;
        }
        return false;
    }

    @Override
    public UserToken login(User user) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", user.getUsername());
        User userGet = baseMapper.selectOne(queryWrapper);
        if (userGet == null) {
            throw new BusinessException(ExceptionEnum.PASSWORD_WRONG);
        }
        String salt = userGet.getSalt();
        if (!userGet.getPassword().equals(MD5Utils.md5(user.getPassword() + salt))) {
            throw new BusinessException(ExceptionEnum.PASSWORD_WRONG);
        }
        if (userGet.getStatus() != 1) {
            throw new BusinessException(ExceptionEnum.NOT_ACTIVED);
        }
        // 创建一个userToken
        UserToken userToken = userTokenService.createUserToken(userGet);
        // 返回userTOken给Controller
        return userToken;
    }

    public Boolean activate(String code) throws Exception {
        try {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(User::getActivationCode, code);
            User user = userMapper.selectOne(queryWrapper);
            if (user == null) {
                throw new BusinessException(
                        ExceptionEnum.ACTIVATION_CODE_INVALID
                );
            }
            if (UserStatusEnum.ACTIVATED.getValue().equals(user.getType())) {
                throw new BusinessException(
                        ExceptionEnum.EMAIL_ACTIVED
                );
            }
            user.setStatus(UserStatusEnum.ACTIVATED.getValue());
            return userMapper.updateById(user) > 0;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("激活失败，code:" + code);
            throw new Exception(e.getMessage());
        }
    }

    @Override
    @Transactional
    public Boolean updatePwd(Integer userId, String oldPassword, String newPassword) {
        User user = baseMapper.selectById(userId);
        String salt = user.getSalt();
        String s = MD5Utils.md5(oldPassword + salt);
        if (!s.equals(user.getPassword())) {
            throw new BusinessException(ExceptionEnum.PASSWORD_WRONG);
        }
        String userNewPwd = MD5Utils.md5(newPassword + salt);
        QueryWrapper<PasswordRecord> pwdQueryWrapper = new QueryWrapper<>();
        pwdQueryWrapper.eq("user_id", user.getId());
        pwdQueryWrapper.eq("password", userNewPwd);
        if (pwdRecordMapper.selectOne(pwdQueryWrapper) != null) {
            throw new BusinessException(ExceptionEnum.PASSWORD_EXISTS);
        }
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", user.getId());
        updateWrapper.set("password", userNewPwd);
        user.setPassword(userNewPwd);
        savePwdRecord(user);
        return userMapper.update(null, updateWrapper) > 0;
    }


    @Override
    public User getUserByColumn(String column, String value) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(column, value);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public boolean updateAvatar(String headerUrl) {
        UserToken userToken = UserTokenThreadLocal.get();
        User userById = baseMapper.selectById(userToken.getUserId());
        userById.setHeaderUrl(headerUrl);
        if (baseMapper.updateById(userById) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public void sendEmail(User user) {
        User emailUser=getUserByColumn("email", user.getEmail());
        if (emailUser == null) {
            throw new BusinessException(ExceptionEnum.EMAIL_NOT_EXISTS);
        }
        String keyResetPwd=UUIDUtils.getId();
        String value=emailUser.getId().toString();
        stringRedisTemplate.opsForValue()
                .set(keyResetPwd, value, SysConsts.RESET_PWD_VALID_TIME, TimeUnit.MINUTES);
        EmailDto emaiDto=new EmailDto();
        String content=String.format(
                "重置密码，点击<a href= '/user/email/verify/%s'>这里</a>跳转至重置密码页面",
                keyResetPwd
        );
        emaiDto.setTitle("Blog系用户密码重置连接");
        emaiDto.setContent(content);
        emaiDto.setRecipient(user.getEmail());
        try {
            emailUtils.sendEmail(emaiDto);
            log.info("发送重置密码邮件成功：" + user.getEmail());
        } catch (Exception e) {
            log.error("发送重置密码邮件失败：" + user.getEmail());
            e.printStackTrace();
        }
    }

    @Override
    public String verifyEmail(String keyResetPwd) {
        String value=stringRedisTemplate.opsForValue().get(keyResetPwd);
        if (ObjectUtils.isEmpty(value)) {
           throw new BusinessException(ExceptionEnum.ACTIVATION_TIME_OUT);
        }
        return keyResetPwd;
    }

    @Override
    public void resetPwd(User user,String code) {
        if (ObjectUtils.isEmpty(code)) {
           return;
        }
        String value=stringRedisTemplate.opsForValue().get(code);
        if (ObjectUtils.isEmpty(value)) {
            throw new BusinessException(ExceptionEnum.ACTIVATION_TIME_OUT);
        }
        user.setId(Integer.valueOf(value));
        String userSalt=SaltUtils.getSalt();
        user.setSalt(userSalt);
        user.setPassword(MD5Utils.md5(user.getPassword() + userSalt));
        baseMapper.updateById(user);
    }

    public boolean savePwdRecord(User user) {
        log.info("保存用户密码记录" + user);
        PasswordRecord passwordRecord = new PasswordRecord();
        passwordRecord.setUserId(user.getId());
        passwordRecord.setPassword(user.getPassword());
        return pwdRecordMapper.insert(passwordRecord) > 0;
    }

}
